home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / tcp / AmigaTCP.lha / AmigaTCP / src / udp.c < prev    next >
C/C++ Source or Header  |  1989-06-24  |  8KB  |  363 lines

  1. /* Send and receive User Datagram Protocol packets */
  2. #include "machdep.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "udp.h"
  6. #include "internet.h"
  7.  
  8. struct udp_cb *udps[NUDP];    /* Hash table for UDP structures */
  9. struct udp_stat udp_stat;    /* Statistics */
  10.  
  11. /* Create a UDP control block for lsocket, so that we can queue
  12.  * incoming datagrams.
  13.  */
  14. int
  15. open_udp(lsocket,r_upcall)
  16. struct socket *lsocket;
  17. void (*r_upcall)();
  18. {
  19.     char *malloc();
  20.     register struct udp_cb *up;
  21.     struct udp_cb *lookup_udp();
  22.     int16 hval,hash_udp();
  23.  
  24.     if((up = lookup_udp(lsocket)) != NULLUDP)
  25.         return 0;    /* Already exists */
  26.     if((up = (struct udp_cb *)malloc(sizeof (struct udp_cb))) == NULLUDP){
  27.         net_error = NO_SPACE;
  28.         return -1;
  29.     }
  30.     up->rcvq = NULLBUF;
  31.     up->rcvcnt = 0;
  32.     up->socket.address = lsocket->address;
  33.     up->socket.port = lsocket->port;
  34.     up->r_upcall = r_upcall;
  35.  
  36.     hval = hash_udp(lsocket);
  37.     up->next = udps[hval];
  38.     up->prev = NULLUDP;
  39.     up->next->prev = up;
  40.     udps[hval] = up;
  41.     return 0;
  42. }
  43.  
  44. /* Send a UDP datagram */
  45. int
  46. send_udp(lsocket,fsocket,tos,ttl,bp,length,id,df)
  47. struct socket *lsocket;        /* Source socket */
  48. struct socket *fsocket;        /* Destination socket */
  49. char tos;                    /* Type-of-service for IP */
  50. char ttl;                    /* Time-to-live for IP */
  51. struct mbuf *bp;            /* Data field, if any */
  52. int16 length;                /* Length of data field */
  53. int16 id;                    /* Optional ID field for IP */
  54. char df;                    /* Don't Fragment flag for IP */
  55. {
  56.     struct mbuf *hbp;
  57.     int16 hdr_len;
  58.     struct pseudo_header ph;
  59.     struct udp_header *uhdr;
  60.  
  61.     if(length == 0 && bp != NULLBUF)
  62.         length = len_mbuf(bp);
  63.     hdr_len = sizeof(struct udp_header);
  64.     length += hdr_len;
  65.  
  66.     /* Allocate UDP protocol header and fill it in */
  67.     if((hbp = alloc_mbuf(hdr_len)) == NULLBUF){
  68.         net_error = NO_SPACE;
  69.         return -1;
  70.     }
  71.     hbp->cnt = hdr_len;
  72.  
  73.     uhdr = (struct udp_header *)hbp->data;
  74.     uhdr->source = htons(lsocket->port);
  75.     uhdr->dest = htons(fsocket->port);
  76.     uhdr->length = htons(length);
  77.     uhdr->checksum = 0;
  78.  
  79.     /* Link in the user data */
  80.     hbp->next = bp;
  81.  
  82.     /* Create IP pseudo-header, compute checksum and send it */
  83.     ph.length = length;
  84.     ph.source = lsocket->address;
  85.     ph.dest = fsocket->address;
  86.     ph.protocol = UDP_PTCL;
  87.     ph.zero = 0;
  88.     /* All zeros and all ones is equivalent in one's complement arithmetic;
  89.      * the spec requires us to change zeros into ones to distinguish an
  90.       * all-zero checksum from no checksum at all
  91.      */
  92.     if((uhdr->checksum = cksum(&ph,hbp,length)) == 0)
  93.         uhdr->checksum = 0xffffffff;
  94.  
  95.     udp_stat.sent++;
  96.     ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,hbp,length,id,df);
  97.     return length;
  98. }
  99.  
  100. /* Accept a waiting datagram, if available. Returns length of datagram */
  101. int
  102. recv_udp(lsocket,fsocket,bp)
  103. struct socket *lsocket;        /* Local socket to receive on */
  104. struct socket *fsocket;        /* Place to stash incoming socket */
  105. struct mbuf **bp;            /* Place to stash data packet */
  106. {
  107.     struct udp_cb *lookup_udp();
  108.     register struct udp_cb *up;
  109.     struct socket *sp;
  110.     struct mbuf *buf;
  111.     int16 length;
  112.  
  113.     up = lookup_udp(lsocket);
  114.     if(up == NULLUDP){
  115.         net_error = NO_CONN;
  116.         return -1;
  117.     }
  118.     if(up->rcvcnt == 0){
  119.         net_error = WOULDBLK;
  120.         return -1;
  121.     }
  122.     buf = dequeue(&up->rcvq);
  123.     up->rcvcnt--;
  124.  
  125.     sp = (struct socket *)buf->data;
  126.     /* Fill in the user's foreign socket structure, if given */
  127.     if(fsocket != NULLSOCK){
  128.         fsocket->address = sp->address;
  129.         fsocket->port = sp->port;
  130.     }
  131.     /* Strip socket header and hand data to user */
  132.     pullup(&buf,NULLCHAR,sizeof(struct socket));
  133.     length = len_mbuf(buf);
  134.     if(bp != (struct mbuf **)NULL)
  135.         *bp = buf;
  136.     else
  137.         free_p(buf);
  138.     return length;
  139. }
  140. /* Delete a UDP control block */
  141. int
  142. del_udp(lsocket)
  143. struct socket *lsocket;
  144. {
  145.     register struct udp_cb *up;
  146.     struct udp_cb *lookup_udp();
  147.     struct mbuf *bp;
  148.     int16 hval;
  149.  
  150.     if((up = lookup_udp(lsocket)) == NULLUDP){
  151.         net_error = INVALID;
  152.         return -1;
  153.     }        
  154.     /* Get rid of any pending packets */
  155.     while(up->rcvcnt != 0){
  156.         bp = up->rcvq;
  157.         up->rcvq = up->rcvq->anext;
  158.         free_p(bp);
  159.         up->rcvcnt--;
  160.     }
  161.     hval = hash_udp(&up->socket);
  162.     if(udps[hval] == up){
  163.         /* First on list */
  164.         udps[hval] = up->next;
  165.         up->next->prev = NULLUDP;
  166.     } else {
  167.         up->prev->next = up->next;
  168.         up->next->prev = up->prev;
  169.     }
  170.     free((char *)up);
  171.     return 0;
  172. }
  173. /* Process an incoming UDP datagram */
  174. void
  175. udp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  176. struct mbuf *bp;
  177. char protocol;
  178. int32 source;        /* Source IP address */
  179. int32 dest;        /* Dest IP address */
  180. char tos;
  181. int16 length;
  182. char rxbroadcast;    /* The only protocol that accepts 'em */
  183. {
  184.     struct pseudo_header ph;
  185.     struct udp_header udp;
  186.     struct udp_cb *up,*lookup_udp();
  187.     struct socket lsocket;
  188.     struct socket *fsocket;
  189.     struct mbuf *sp;
  190.     int ckfail = 0;
  191.  
  192.     if(bp == NULLBUF)
  193.         return;
  194.  
  195.     udp_stat.rcvd++;
  196.  
  197.     /* Create pseudo-header and verify checksum */
  198.     ph.source = source;
  199.     ph.dest = dest;
  200.     ph.protocol = protocol;
  201.     ph.length = length;
  202.     ph.zero = 0;
  203.     if(cksum(&ph,bp,length) != 0)
  204.         /* Checksum apparently failed, note for later */
  205.         ckfail++;
  206.  
  207.     /* Extract UDP header in host order */
  208.     pullup(&bp,(char *)&udp,sizeof(struct udp_header));
  209.  
  210.     /* If the checksum field is zero, then ignore a checksum error.
  211.      * I think this is dangerously wrong, but it is in the spec.
  212.      */
  213.     if(ckfail && udp.checksum != 0){
  214.         udp_stat.cksum++;
  215.         free_p(bp);
  216.         return;
  217.     }
  218.     udp.dest = ntohs(udp.dest);
  219.     udp.source = ntohs(udp.source);
  220.  
  221.     /* If this was a broadcast packet, pretend it was sent to us */
  222.     if(rxbroadcast){
  223.         lsocket.address = ip_addr;
  224.         udp_stat.bdcsts++;
  225.     } else
  226.         lsocket.address = dest;
  227.  
  228.     lsocket.port = udp.dest;
  229.     /* See if there's somebody around to read it */
  230.     if((up = lookup_udp(&lsocket)) == NULLUDP){
  231.         /* Nope, toss it on the floor */
  232.         udp_stat.unknown++;
  233.         free_p(bp);
  234.         return;
  235.     }
  236.     /* Create a buffer which will contain the foreign socket info */
  237.     if((sp = alloc_mbuf(sizeof(struct socket))) == NULLBUF){
  238.         /* No space, drop whole packet */
  239.         free_p(bp);
  240.         return;
  241.     }
  242.     sp->cnt = sizeof(struct socket);
  243.  
  244.     fsocket = (struct socket *)sp->data;
  245.     fsocket->address = source;
  246.     fsocket->port = udp.source;
  247.  
  248.     /* Yes, remove the now redundant UDP header, chain the foreign socket
  249.      * info in front of it and queue it
  250.      */
  251.  
  252.     sp->next = bp;
  253.     enqueue(&up->rcvq,sp);
  254.     up->rcvcnt++;
  255.     if(up->r_upcall)
  256.         (*up->r_upcall)(&lsocket,up->rcvcnt);
  257. }
  258. /* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
  259. static
  260. struct udp_cb *
  261. lookup_udp(socket)
  262. struct socket *socket;
  263. {
  264.     register struct udp_cb *up;
  265.     int16 hash_udp();
  266.  
  267.     up = udps[hash_udp(socket)];
  268.     while(up != NULLUDP){
  269.         if(bcmp((char *)socket,(char *)&up->socket,sizeof(struct socket)) == 0)
  270.             break;
  271.         up = up->next;
  272.     }
  273.     return up;
  274. }
  275.  
  276. /* Hash a UDP socket (address and port) structure */
  277. static
  278. int16
  279. hash_udp(socket)
  280. struct socket *socket;
  281. {
  282.     int16 hval;
  283.  
  284.     /* Compute hash function on socket structure */
  285.     hval = hiword(socket->address);
  286.     hval ^= loword(socket->address);
  287.     hval ^= socket->port;
  288.     hval %= NUDP;
  289.     return hval;
  290. }
  291. #ifdef    TRACE
  292. /* Dump UDP statistics and control blocks */
  293. doudpstat()
  294. {
  295.     extern struct udp_stat udp_stat;
  296.     char *psocket();
  297.     register struct udp_cb *udp;
  298.     register int i;
  299.  
  300.     printf("sent %u rcvd %u bdcsts %u cksum err %u unknown socket %u\r\n",
  301.     udp_stat.sent,udp_stat.rcvd,udp_stat.bdcsts,udp_stat.cksum,udp_stat.unknown);
  302. #ifdef    AMIGA
  303.     printf("&UCB   Rcv-Q  Local socket\r\n");
  304. #else
  305.     printf("&UCB Rcv-Q  Local socket\r\n");
  306. #endif
  307.     for(i=0;i<NUDP;i++){
  308.         for(udp = udps[i];udp != NULLUDP; udp = udp->next){
  309. #ifdef    AMIGA
  310.             printf("%6lx%6u  %s\r\n",(unsigned long)udp,udp->rcvcnt,
  311. #else
  312.             printf("%x%6u  %s\r\n",(int)udp,udp->rcvcnt,
  313. #endif
  314.              psocket(&udp->socket));
  315.         }
  316.     }
  317. }
  318. /* Dump a UDP header */
  319. void
  320. udp_dump(bp,source,dest,check)
  321. struct mbuf *bp;
  322. int32 source,dest;
  323. int check;        /* If 0, bypass checksum verify */
  324. {
  325.     register struct udp_header *udph;
  326.     struct pseudo_header ph;
  327.     int i;
  328.     char tmpbuf;
  329.  
  330.     if(bp == NULLBUF)
  331.         return;
  332.     /* If packet isn't in a single buffer, make a temporary copy and
  333.      * note the fact so we free it later
  334.      */
  335.     if(bp->next != NULLBUF){
  336.         bp = copy_p(bp,len_mbuf(bp));
  337.         tmpbuf = 1;
  338.     } else
  339.         tmpbuf = 0;
  340.  
  341.     udph = (struct udp_header *)bp->data;
  342.     printf("UDP:");
  343.     printf(" %u->%u",ntohs(udph->source),
  344.         ntohs(udph->dest));
  345.     printf(" len %u",ntohs(udph->length));
  346.     
  347.     if(check){
  348.         /* Verify checksum */
  349.         ph.source = source;
  350.         ph.dest = dest;
  351.         ph.zero = 0;
  352.         ph.protocol = UDP_PTCL;
  353.         ph.length = len_mbuf(bp);
  354.         if(udph->checksum != 0 && (i = cksum(&ph,bp,ph.length)) != 0)
  355.             printf(" CHECKSUM ERROR (%u)",i);
  356.     }
  357.     printf("\r\n");
  358.     if(tmpbuf)
  359.         free_p(bp);
  360. }
  361.  
  362. #endif
  363.